package org.longteng.sensitive.mybatis.intercepts;

import org.longteng.sensitive.annotation.SensitiveDataEntity;
import org.longteng.sensitive.ISensitiveDataEncrypt;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.resultset.ResultSetHandler;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.sql.Statement;
import java.util.List;
import java.util.Objects;

/**
 * 结果集拦截器，对敏感数据进行解密，目前只针对String类型进行加密解密
 * <br>用jasypt3.0(PBEWITHHMACSHA512ANDAES_256)加密
 */
@Intercepts({
        @Signature(type = ResultSetHandler.class, method = "handleResultSets", args = {Statement.class})
})
@Component
@Slf4j
public class ResultSetInterceptor implements Interceptor {
    /**注入数据加解密实现
     * <br>需要在启动应用中用@Bean构建ISensitiveDataEncrypt的实现类
     * */
    private ISensitiveDataEncrypt sensitiveDataEncrypt;
    @Resource
    public void setSensitiveDataEncrypt(ISensitiveDataEncrypt sensitiveDataEncrypt) {
        this.sensitiveDataEncrypt = sensitiveDataEncrypt;
        log.info("注入数据加解密实现:{}", sensitiveDataEncrypt.getClass());
    }

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        if (log.isDebugEnabled()) {
            log.debug("查询结果拦截解密.");
        }
        // 取出查询的结果
        Object resultObject = invocation.proceed();
        if (Objects.isNull(resultObject)) {
            return null;
        }
        // 基于selectList
        if (resultObject instanceof List<?>) {
            List<?> resultList = (List<?>) resultObject;
            if (!CollectionUtils.isEmpty(resultList) && needToDecrypt(resultList.get(0))) {
                for (Object obj : resultList) {
                    sensitiveDataEncrypt.decrypt(obj);
                }
            }
        } else {
            if (needToDecrypt(resultObject)) {
                sensitiveDataEncrypt.decrypt(resultObject);
            }
        }
        return resultObject;
    }

    /**
     * 实体是否需要敏感数据解密
     * @param object
     * @return
     */
    private boolean needToDecrypt(Object object) {
        Class<?> objectClass = object.getClass();
        SensitiveDataEntity sensitiveClass = AnnotationUtils.findAnnotation(objectClass, SensitiveDataEntity.class);
        return Objects.nonNull(sensitiveClass);
    }
}
